﻿// /*------------------------------------------------------------
// 工程名:    Ensemble2D
// 文件名:    EnsembleEditorApp.cs
// 编写人:    yhh
// 编写日期: 上午 10:07
// -------------------------------------------------------------*/

using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using Ensemble;
using Ensemble2D.Forms;
using Ensemble2D.Plugin;
using NLog;

namespace Ensemble2D
{
    public static class EnsembleEditorApp
    {
        private static readonly Logger logger = LogManager.GetCurrentClassLogger();
        public const string EditorLogfilePath = "logfile_editor.txt";

        private static bool needsRecovery = false;
        private static MainForm mainForm = null;
        private static EditorPluginManager pluginManager = new EditorPluginManager();
        private static ReloadCorePluginDialog corePluginReloader = null;
        private static string launcherApp = null;

        public static string LauncherAppPath
        {
            get
            {
                var launcherPath = string.IsNullOrWhiteSpace(launcherApp)
                    ? EditorHelper.EnsembleLauncherExecFile
                    : launcherApp;

                if (!Path.IsPathRooted(launcherPath))
                {
                    var appDirLauncherApp = Path.Combine(PathHelper.ExecutingAssemblyDir, launcherPath);
                    if (File.Exists(appDirLauncherApp)) return appDirLauncherApp;
                }

                return EditorHelper.EnsembleLauncherExecFile;
            }
            set
            {
                if (Path.GetFullPath(value) == Path.GetFullPath(EditorHelper.EnsembleLauncherExecFile)) value = null;
                if (value != launcherApp)
                {
                    launcherApp = value;
                    UpdatePluginSourceCode();
                }
            }
        }

        public static void UpdatePluginSourceCode()
        {
            
        }

        public static void Init(MainForm mainForm, bool recover)
        {
            needsRecovery = recover;
            EnsembleEditorApp.mainForm = mainForm;

            if (!Directory.Exists(EnsembleApp.DataDirectory))
            {
                Directory.CreateDirectory(EnsembleApp.DataDirectory);
                using (var s = File.OpenWrite(Path.Combine(EnsembleApp.DataDirectory, "WorkingFolderIcon.ico")))
                {
                    GeneralResCache.IconWorkingFolder.Save(s);
                }
                using (var w = new StreamWriter(Path.Combine(EnsembleApp.DataDirectory,"desktop.ini")))
                {
                    w.WriteLine("[.ShellClassInfo]");
                    w.WriteLine("ConfirmFileOp=0");
                    w.WriteLine("NoSharing=0");
                    w.WriteLine("IconFile=WorkingFolderIcon.ico");
                    w.WriteLine("IconIndex=0");
                    w.WriteLine("InfoTip=这是引擎的工作路径");
                }

                var info = new DirectoryInfo(EnsembleApp.DataDirectory);
                info.Attributes |= FileAttributes.System;

                var fileInfoDestop = new FileInfo(Path.Combine(EnsembleApp.DataDirectory,"desktop.ini"));
                fileInfoDestop.Attributes |= FileAttributes.Hidden;

                var fileInfoIcon = new FileInfo(Path.Combine(EnsembleApp.DataDirectory,"WorkingFolderIcon.ico"));
                fileInfoIcon.Attributes |= FileAttributes.Hidden;
            }
            if (!Directory.Exists(EnsembleApp.PluginDirectory)) 
                Directory.CreateDirectory(EnsembleApp.PluginDirectory);
            
            /*EnsembleApp.PluginManager.PluginsReady += pluginManager_PluginsReady;
            EnsembleApp.Init(
                EnsembleApp.ExecutionEnvironment.Editor,
                EnsembleApp.ExecutionContext.Editor,
                new DefaultPluginLoader(), 
                null);

            pluginManager.Init(EnsembleApp.PluginManager.PluginLoader);*/
        }

        private static void pluginManager_PluginsReady(object sender, EnsemblePluginEventArgs e)
        {
            foreach (CorePlugin plugin in e.Plugins)
            {
                AnalyzeCorePlugin(plugin);
            }
        }

        public static void SaveAllProjectData()
        {
            
        }

        private static void AnalyzeCorePlugin(CorePlugin plugin)
        {
            logger.Info("分析核心插件: {0}",plugin.AsmName);

            var asmRefQuery = from AssemblyName a in plugin.PluginAssembly.GetReferencedAssemblies()
                select a.GetShortAssemblyName();
            string thisAsmName = typeof(EnsembleEditorApp).Assembly.GetShortAssemblyName();
            foreach (var asmName in asmRefQuery)
            {
                bool illegalRef = false;

                if (asmName == thisAsmName)
                {
                    illegalRef = true;
                }
                else if(pluginManager.LoadedPlugins.Any(p => p.PluginAssembly.GetShortAssemblyName() == asmName))
                {
                    illegalRef = true;
                }

                if (illegalRef)
                {
                    logger.Warn("发现非法引用 '{0}'." +
                        "核心插件不应该参考使用EnsembleEditor或者其他EditorPlugins。关键代码请移动到EdtiorPlugin",asmName);
                }
            }

            Type[] expoertedTypes;
            try
            {
                expoertedTypes = plugin.PluginAssembly.GetExportedTypes();
            }
            catch (Exception e)
            {
                logger.Error("无法分析导出的类型:{0}",e);
                expoertedTypes = null;
            }

            if (expoertedTypes != null)
            {
                var cmpTypeQuery = from Type t in expoertedTypes
                    where typeof(Component).IsAssignableFrom(t)
                    select t;
                foreach (var cmpType in cmpTypeQuery)
                {
                    var fileds = cmpType.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public |
                                                   BindingFlags.Instance);
                    if (fileds.Length > 0)
                    {
                        logger.Warn("在组件中找到公共字段 '{0}' : {1}." +
                                    "公共字段在公共类当中是不允许使用的，考虑使用属性。", cmpType.GetTypeCSCodeName(true),
                            fileds.ToString(f => FieldInfo(f, false), ","));
                    }
                }
            }
        }

        private static string FieldInfo(FieldInfo info, bool includeDeclaringType = true)
        {
            if (info == null) return "null";
            var declTypeName = Type(info.DeclaringType);
            var fieldTypeName = Type(info.FieldType);
            return string.Format(CultureInfo.InvariantCulture, "{0} {1}{2}", fieldTypeName,
                includeDeclaringType ? declTypeName + "." : "", info.Name);
        }

        private static string Type(Type type)
        {
            if (type == null) return "null";
            return type.GetTypeCSCodeName(true);
        }
    }
}